<?php
/**
 * MineAdmin is committed to providing solutions for quickly building web applications
 * Please view the LICENSE file that was distributed with this source code,
 * For the full copyright and license information.
 * Thank you very much for using MineAdmin.
 *
 * @Author X.Mo<root@imoi.cn>
 * @Link   https://gitee.com/xmo/MineAdmin
 */

declare(strict_types=1);

namespace Newbie;

use DI\Attribute\Inject;
use Psr\Container\ContainerInterface;
use Symfony\Component\Filesystem\Filesystem;

class Newbie {
    /**
     * @var string
     */
    private static string $version = '1.1.0';

    /**
     * @var string
     */
    private string $appPath = '';

    /**
     * @var array
     */
    private array $moduleInfo = [];

    /**
     * ContainerInterface
     */
    #[Inject]
    protected ContainerInterface $container;

    /**
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function __construct () {
        $this->setAppPath(BASE_PATH . '/app');
        $this->scanModule();
    }

    /**
     * @return string
     */
    public static function getRootPath (): string {
        $directory = __DIR__;
        while (strpos($directory, 'runtime') > 0) {
            $directory = dirname($directory);
        }
        return $directory . DIRECTORY_SEPARATOR;
    }

    /**
     * @param string $id
     * @return mixed
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function app (string $id): object {
        return container()->get($id);
    }

    /**
     * @return ContainerInterface
     */
    public function getContainer (): ContainerInterface {
        return container();
    }

    /**
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function scanModule (): void {
        $infos   = [];
        $modules = glob(self::getAppPath() . '*');
        //echo self::getAppPath() . '*'.PHP_EOL;
        foreach ($modules as &$mod) {
            //echo 'SCAN:'.$mod.date('Y-m-d H:i:s').PHP_EOL;
            if (is_dir($mod)) {
                $modInfo = $mod . DIRECTORY_SEPARATOR . 'config.json';
                if (file_exists($modInfo)) {
                    $infos[basename($mod)] = json_decode(file_get_contents($modInfo), true);
                }
            }
        }
        $this->setModuleInfo($infos);
    }

    /**
     * @return string
     */
    public static function getVersion (): string {
        return self::$version;
    }

    /**
     * @return mixed
     */
    public function getAppPath (): string {
        return $this->appPath . DIRECTORY_SEPARATOR;
    }

    /**
     * @param mixed $appPath
     */
    public function setAppPath (string $appPath): void {
        $this->appPath = $appPath;
    }

    /**
     * @param string|null $name
     * @return mixed
     */
    public function getModuleInfo (string $name = null): array {
        if (empty($name)) {
            return $this->moduleInfo;
        }
        return $this->moduleInfo[$name] ?? [];
    }

    /**
     * @param mixed $moduleInfo
     */
    public function setModuleInfo ($moduleInfo): void {
        $this->moduleInfo = $moduleInfo;
    }

    /**
     * @param String $key
     * @param string $value
     * @param false $save
     * @return bool
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    public function setModuleConfigValue (string $key, string $value, bool $save = false): bool {
        if (strpos($key, '.') > 0) {
            list($mod, $name) = explode('.', $key);
            if (isset($this->moduleInfo[$mod]) && isset($this->moduleInfo[$mod][$name])) {
                $this->moduleInfo[$mod][$name] = $value;
                $save && $this->saveModuleConfig($mod);
                return true;
            }
        }
        return false;
    }

    /**
     * @param string $mod
     * @throws \Psr\Container\ContainerExceptionInterface
     * @throws \Psr\Container\NotFoundExceptionInterface
     */
    protected function saveModuleConfig (string $mod): void {
        if (!empty($mod)) {
            $fs      = $this->app(Filesystem::class);
            $modJson = $this->getAppPath() . $mod . DIRECTORY_SEPARATOR . 'config.json';
            if (!$fs->isWritable($modJson)) {
                $fs->chmod($modJson, 666);
            }
            $fs->put($modJson, \json_encode($this->getModuleInfo($mod), JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
        }
    }
}